package com.sensor.meter.widget

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.RadialGradient
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.Shader
import android.graphics.SweepGradient
import android.util.AttributeSet
import android.view.View
import com.sensor.meter.R
import com.sensor.meter.utils.dp2px
import com.sensor.meter.utils.sp2px
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.sin

class DashboardView
  @JvmOverloads
  constructor(context: Context?,val attributeSet: AttributeSet? = null, defStyleAttr: Int = 0)
  : View(context, attributeSet, defStyleAttr) {

  private var alreadyMax = false
  private var mCenterX = 0f
  private var mCenterY = 0f
  private var mCreditValue = 0
  private var mDateFormat: SimpleDateFormat? = null
  private var mHeaderText = "LUX"
  private var mLength1 = 0f
  private var mLength2 = 0f
  private var mMax = 1000.0f
  private var mMin = 0.0f
  private var mPadding = 0
  private var mPaint: Paint? = null
  private var mPath: Path? = null
  private var mProgressWidth = 0
  private var mRadius = 0
  private var mRectFProgressArc: RectF? = null
  private var mRectText: Rect? = null
  private var mSparkleWidth = 0
  /** 起始弧度位置 */
  private val mStartAngle = 150
  /** 表针弧度 */
  private val mSweepAngle = 240
  /** 半径值 */
  private var diameter=220
  /** 表盘颜色 */
  private var dialColor=Color.WHITE

  init {
    initAttr()
  }

  @SuppressLint("Recycle", "CustomViewStyleable")
  private fun initAttr() {
    //setBackgroundColor(Color.BLUE)

    val typedArr=context!!.obtainStyledAttributes(attributeSet, R.styleable.DashBoard)
    //
    mSparkleWidth=context.dp2px(typedArr.getDimensionPixelSize(R.styleable.DashBoard_sparkle_width,10).toFloat()).toInt()
    mProgressWidth = context.dp2px(typedArr.getDimensionPixelSize(R.styleable.DashBoard_progress_width,4).toFloat()).toInt()
    mMax=typedArr.getFloat(R.styleable.DashBoard_max_value,1000.0f)
    mMin=typedArr.getFloat(R.styleable.DashBoard_min_value,0.0f)

    if(typedArr.hasValue(R.styleable.DashBoard_diameter)){
      diameter=typedArr.getInt(R.styleable.DashBoard_diameter,220)
    }
    if(typedArr.hasValue(R.styleable.DashBoard_unit)){
      mHeaderText= typedArr.getString(R.styleable.DashBoard_unit).toString()
    }
    if(typedArr.hasValue(R.styleable.DashBoard_text)){
      //
    }
    if(typedArr.hasValue(R.styleable.DashBoard_dial_color)){
      dialColor=typedArr.getColor(R.styleable.DashBoard_dial_color,Color.WHITE)
    }

    //
    typedArr.recycle()
    // 画笔
    mPaint = Paint()
    //是否抗锯齿
    mPaint!!.isAntiAlias = true
    //画笔的线冒样式
    mPaint!!.strokeCap = Paint.Cap.SQUARE
    //颜色
    mPaint!!.setColor(dialColor)
    mRectFProgressArc = RectF()
    mRectText = Rect()
    mPath = Path()
  }

  override fun onMeasure(widthMeasureSpec:Int, heightMeasureSpec:Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    // padding 最大值
    mPadding = max(max(paddingLeft, paddingTop), max(paddingRight, paddingBottom))
    setPadding(mPadding, mPadding, mPadding, mPadding)

    mLength1 = mPadding + mSparkleWidth / 2.0f + context.dp2px(8.0f)
    mLength2 = mLength1 + mProgressWidth + context.dp2px(4.0f)
    // 计算仪表盘直径值
    val resolveSize = resolveSize(context.dp2px(diameter.toFloat()).toInt(), widthMeasureSpec)
    mRadius = (resolveSize - mPadding * 2) / 2
    //
    setMeasuredDimension(resolveSize, resolveSize - context.dp2px(50.0f).toInt())

    val mdWidth = measuredWidth / 2.0f
    mCenterY = mdWidth
    mCenterX = mdWidth
    val rectF = mRectFProgressArc
    val lt= mPadding + mSparkleWidth / 2.0f
    val rb= measuredWidth - mPadding - mSparkleWidth / 2.0f
    //rectF!!.set(lt,lt,rb,rb) kotlin 另一种写法
    rectF!![lt, lt, rb] = rb
    mPaint!!.textSize = context.sp2px(10.0f)
    mPaint!!.getTextBounds("0", 0, 1, mRectText)
  }

  override fun onDraw(canvas: Canvas) {
    super.onDraw(canvas)
    val coordinatePoint: FloatArray

    mPaint!!.style = Paint.Style.STROKE
    mPaint!!.strokeWidth = mProgressWidth.toFloat()
    // 透明度设置为80
    mPaint!!.setAlpha(80)
    //外部圆环
    canvas.drawArc(mRectFProgressArc!!, mStartAngle.toFloat(), mSweepAngle.toFloat(), false, mPaint!!)
    // 进度指针
    mPaint!!.setAlpha(255)
    mPaint!!.setShader(generateSweepGradient())
    canvas.drawArc(mRectFProgressArc!!, mStartAngle.toFloat(), calculateRelativeAngleWithValue(mCreditValue), false, mPaint!!)

    coordinatePoint = if (alreadyMax) {
      getCoordinatePoint(mRadius - mSparkleWidth / 2.0f, mStartAngle + calculateRelativeAngleWithValue(mMax.toInt()))
    } else {
      getCoordinatePoint(mRadius - mSparkleWidth / 2.0f, mStartAngle + calculateRelativeAngleWithValue(mCreditValue))
    }

    mPaint!!.style = Paint.Style.FILL
    mPaint!!.setShader(generateRadialGradient(coordinatePoint[0], coordinatePoint[1]))
    // 进度坐标点
    canvas.drawCircle(coordinatePoint[0], coordinatePoint[1], mSparkleWidth / 2.0f, mPaint!!)

    // 表针的弧度
    val calculateRelativeAngleWithValue = calculateRelativeAngleWithValue(mCreditValue)
    mPaint!!.setShader(null)
    mPaint!!.setAlpha(if (calculateRelativeAngleWithValue >= mSweepAngle / 2.0f) 200 else 80)
    canvas.save()

    // 画线
    canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1.0f, mPaint!!)
    //
    var range=0F
    val degrees=mSweepAngle / ((mMax - mMin) / 10.0f)
    var degreesAngleWithValue=mSweepAngle / 2.0f

    while (range < (mMax - mMin) / 2.0f / 10.0f){
      canvas.rotate(-degrees, mCenterX, mCenterY)
      degreesAngleWithValue -= degrees
      mPaint!!.setAlpha(if (calculateRelativeAngleWithValue >= degreesAngleWithValue) 200 else 80)
      canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1.0f, mPaint!!)
      range++
    }
    canvas.restore()
    canvas.save()
    //
    range=0f
    degreesAngleWithValue=mSweepAngle / 2.0f
    while (range < (mMax - mMin) / 2.0f / 10.0f) {
      canvas.rotate(degrees, mCenterX, mCenterY)
      val d = degreesAngleWithValue + degrees
      mPaint!!.setAlpha(if (calculateRelativeAngleWithValue >= d) 200 else 80)
      canvas.drawLine(mCenterX, mPadding + mLength1, mCenterX, mPadding + mLength1 - 1.0f, mPaint!!)
      degreesAngleWithValue = d
      range++
    }
    canvas.restore()

    if (!alreadyMax) {
      canvas.save()
      canvas.rotate(calculateRelativeAngleWithValue - mSweepAngle / 2.0f, mCenterX, mCenterY)
      mPaint!!.setAlpha(255)
      mPaint!!.style = Paint.Style.FILL
      mPath!!.reset()
      mPath!!.moveTo(mCenterX, mPadding + mLength2)
      mPath!!.rLineTo(-context.dp2px(2.0f), context.dp2px(5.0f))
      mPath!!.rLineTo(context.dp2px(4.0f), 0.0f)
      mPath!!.close()
      canvas.drawPath(mPath!!, mPaint!!)
      mPaint!!.strokeWidth = context.dp2px(1.0f)
      mPaint!!.style = Paint.Style.STROKE
      canvas.drawCircle(mCenterX, mPadding + mLength2 + context.dp2px(6.0f) + 1.0f, context.dp2px(2.0f), mPaint!!)
      canvas.restore()
    } else {
      mPaint!!.setAlpha(255)
    }
    mPaint!!.style = Paint.Style.FILL
    mPaint!!.textSize = context.sp2px(35.0f)
    mPaint!!.textAlign = Paint.Align.CENTER
    // Lux 值
    canvas.drawText(mCreditValue.toString(), mCenterX, mCenterY, mPaint!!)
    mPaint!!.textSize = context.sp2px(16.0f)
    // Lux 描述
    canvas.drawText(calculateCreditDescription(), mCenterX, mCenterY - context.dp2px(40.0f), mPaint!!)
    mPaint!!.setAlpha(160)
    mPaint!!.textSize = context.sp2px(20.0f)
    // Lux 单位
    canvas.drawText(mHeaderText, mCenterX, mCenterY - context.dp2px(65.0f), mPaint!!)
    mPaint!!.setAlpha(160)
    mPaint!!.textSize = context.sp2px(12.0f)
    // 采集时间
    canvas.drawText(formatTimeStr, mCenterX, mCenterY + context.dp2px(25.0f), mPaint!!)
  }


  private fun generateSweepGradient(): SweepGradient {
    val sweepGradient = SweepGradient(mCenterX, mCenterY, intArrayOf(Color.argb(0, 255, 255, 255), Color.argb(200, 255, 255, 255)), floatArrayOf(0.0f, calculateRelativeAngleWithValue(mCreditValue) / 360.0f))
    val matrix = Matrix()
    matrix.setRotate((mStartAngle - 1).toFloat(), mCenterX, mCenterY)
    sweepGradient.setLocalMatrix(matrix)
    return sweepGradient
  }

  private fun generateRadialGradient(f: Float, f2: Float): RadialGradient {
    return RadialGradient(f, f2, mSparkleWidth / 2.0f, intArrayOf(Color.argb(255, 255, 255, 255), Color.argb(80, 255, 255, 255)), floatArrayOf(0.4f, 1.0f), Shader.TileMode.CLAMP)
  }

  /**
   * 进度圆点的位置
   * @param cpx Float   圆点x坐标点
   * @param cpy Float  圆点y坐标点
   * @return FloatArray
   */
  private fun getCoordinatePoint(cpx: Float, cpy: Float): FloatArray {
    val fArr = FloatArray(2)
    val radians = Math.toRadians(cpy.toDouble()).toFloat()
    if (cpy < ANGLE_90) {
      fArr[0] = mCenterX + cos(radians) * cpx
      fArr[1] = mCenterY + sin(radians) * cpx
    } else {
      val radian = if (cpy > ANGLE_90) 1 else if (cpy.equals(ANGLE_90)) 0 else -1
      if (radian == ANGLE_0) {
        fArr[0] = mCenterX
        fArr[1] = mCenterY + cpx
      } else if (radian <= ANGLE_0 || cpy >= ANGLE_180) {
        val radian2 = if (cpy > ANGLE_180) 1 else if (cpy.equals(ANGLE_180)) 0 else -1
        if (radian2 == ANGLE_0) {
          fArr[0] = mCenterX - cpx
          fArr[1] = mCenterY
        } else if (radian2 > ANGLE_0 && cpy < ANGLE_270) {
          val d2 = (cpy - ANGLE_180) * Math.PI / ANGLE_180
          fArr[0] = mCenterX - cos(d2).toFloat() * cpx
          fArr[1] = mCenterY - sin(d2).toFloat() * cpx
        } else if (cpy == ANGLE_270) {
          fArr[0] = mCenterX
          fArr[1] = mCenterY - cpx
        } else {
          val d4 = (ANGLE_360 - cpy) * Math.PI / ANGLE_180
          fArr[0] = mCenterX + cos(d4).toFloat() * cpx
          fArr[1] = mCenterY - sin(d4).toFloat() * cpx
        }
      } else {
        val d6 = (ANGLE_180 - cpy) * Math.PI / ANGLE_180
        fArr[0] = mCenterX - cos(d6).toFloat() * cpx
        fArr[1] = mCenterY + sin(d6).toFloat() * cpx
      }
    }
    return fArr
  }

  /**
   * 计算表针的弧度
   * @param value Int
   * @return Float
   */
  private fun calculateRelativeAngleWithValue(value: Int): Float {
    return mSweepAngle * value * 1.0f / mMax
  }

  /**
   * lux 描述
   * @return String
   */
  private fun calculateCreditDescription(): String {
    return if (mCreditValue.toFloat() >= mMax) "爆表啦"
    else if (mCreditValue >= 1000) "过亮"
    else if (mCreditValue >= 300) "明亮"
    else if (mCreditValue >= 150) "好"
    else if (mCreditValue >= 50) "较好"
    else if (mCreditValue >= 10) "一般"
    else if (mCreditValue >= 3) "较暗"
    else "暗"
  }

  private val formatTimeStr: String
    get() {
      if (mDateFormat == null) {
        mDateFormat = SimpleDateFormat("HH:mm:ss", Locale.CHINA)
      }
      return String.format("测量时间：%s", mDateFormat!!.format(Date()))
    }

  /** 设置进度数据 */
  var creditValue: Int
    get() = mCreditValue
    set(value) {
      if (mCreditValue == value || value < mMin) {
        return
      }
      alreadyMax = mCreditValue > mMax
      mCreditValue = value
      postInvalidate()
    }

  companion object{
    const val ANGLE_0=0
    const val ANGLE_90=90.0f
    const val ANGLE_180=180.0f
    const val ANGLE_270=270.0f
    const val ANGLE_360=360.0f
  }

}


